(function (window, T, string, browser) {
    var dom = T.dom = {};
    
    /**
     * 从文档中获取指定的DOM元素
     * @name dom.g
     * @function
     * @grammar dom.g(id)
     * @param {string|HTMLElement} id 元素的id或DOM元素.
     * @shortcut g,T.G
     * @meta standard
     * @see dom.q
     *
     * @return {HTMLElement|null} 获取的元素，查找不到时返回null,如果参数不合法，直接返回参数.
     */
    dom.g = function(id) {
        if (!id) return null; //修改IE下dom.g(dom.g('dose_not_exist_id'))报错的bug，by Meizz, dengping
        if ('string' == typeof id || id instanceof String) {
            return document.getElementById(id);
        } else if (id.nodeName && (id.nodeType == 1 || id.nodeType == 9)) {
            return id;
        }
        return null;
    };


    /**
     * 为目标元素添加className
     * @name dom.addClass
     * @function
     * @grammar dom.addClass(element, className)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {string} className 要添加的className，允许同时添加多个class，中间使用空白符分隔
     * @remark
     * 使用者应保证提供的className合法性，不应包含不合法字符，className合法字符参考：http://www.w3.org/TR/CSS2/syndata.html。
     * @shortcut addClass
     * @meta standard
     * @see dom.removeClass
     *  
     *              
     * @returns {HTMLElement} 目标元素
     */
    dom.addClass = function (element, className) {
        element = dom.g(element);
        var classArray = className.split(/\s+/),
            result = element.className,
            classMatch = " " + result + " ",
            i = 0,
            l = classArray.length;

        for (; i < l; i++){
             if ( classMatch.indexOf( " " + classArray[i] + " " ) < 0 ) {
                 result += (result ? ' ' : '') + classArray[i];
             }
        }

        element.className = result;
        return element;
    };

    /**
     * 获取目标元素的直接子元素列表
     * @name dom.children
     * @function
     * @grammar dom.children(element)
     * @param {HTMLElement|String} element 目标元素或目标元素的id
     * @meta standard
     *             
     * @returns {Array} 目标元素的子元素列表，没有子元素时返回空数组
     */
    dom.children = function (element) {
        element = dom.g(element);

        for (var children = [], tmpEl = element.firstChild; tmpEl; tmpEl = tmpEl.nextSibling) {
            if (tmpEl.nodeType == 1) {
                children.push(tmpEl);
            }
        }
        
        return children;    
    };

    /**
     * 判断一个元素是否包含另一个元素
     * @name dom.contains
     * @function
     * @grammar dom.contains(container, contained)
     * @param {HTMLElement|string} container 包含元素或元素的id
     * @param {HTMLElement|string} contained 被包含元素或元素的id
     * @meta standard
     * @see dom.intersect
     *             
     * @returns {boolean} contained元素是否被包含于container元素的DOM节点上
     */
    dom.contains = function (container, contained) {

        var g = dom._g;
        container = g(container);
        contained = g(contained);

        //fixme: 无法处理文本节点的情况(IE)
        return container.contains
            ? container != contained && container.contains(contained)
            : !!(container.compareDocumentPosition(contained) & 16);
    };

    /**
     * 提供给setAttr与getAttr方法作名称转换使用
     * ie6,7下class要转换成className
     * @meta standard
     */

    dom._NAME_ATTRS = (function () {
        var result = {
            'cellpadding': 'cellPadding',
            'cellspacing': 'cellSpacing',
            'colspan': 'colSpan',
            'rowspan': 'rowSpan',
            'valign': 'vAlign',
            'usemap': 'useMap',
            'frameborder': 'frameBorder'
        };
        
        if (browser.ie < 8) {
            result['for'] = 'htmlFor';
            result['class'] = 'className';
        } else {
            result['htmlFor'] = 'for';
            result['className'] = 'class';
        }
        
        return result;
    })();


    /**
     * 设置目标元素的attribute值
     * @name dom.setAttr
     * @function
     * @grammar dom.setAttr(element, key, value)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {string} key 要设置的attribute键名
     * @param {string} value 要设置的attribute值
     * @remark
     * 
                设置object的自定义属性时，由于浏览器限制，无法设置。
            
     * @shortcut setAttr
     * @meta standard
     * @see dom.getAttr,dom.setAttrs
     *             
     * @returns {HTMLElement} 目标元素
     */
    dom.setAttr = function (element, key, value) {
        element = dom.g(element);

        if ('style' == key){
            element.style.cssText = value;
        } else {
            key = dom._NAME_ATTRS[key] || key;
            element.setAttribute(key, value);
        }

        return element;
    };

    /**
     * 批量设置目标元素的attribute值
     * @name dom.setAttrs
     * @function
     * @grammar dom.setAttrs(element, attributes)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {Object} attributes 要设置的attribute集合
     * @shortcut setAttrs
     * @meta standard
     * @see dom.setAttr,dom.getAttr
     *             
     * @returns {HTMLElement} 目标元素
     */
    dom.setAttrs = function (element, attributes) {
        element = dom.g(element);

        for (var key in attributes) {
            dom.setAttr(element, key, attributes[key]);
        }

        return element;
    };


    /**
     * 创建 Element 对象。
     * @author berg
     * @name dom.create
     * @function
     * @grammar dom.create(tagName[, options])
     * @param {string} tagName 标签名称.
     * @param {Object} opt_attributes 元素创建时拥有的属性，如style和className.
     * @version 1.3
     * @meta standard
     * @returns {HTMLElement} 创建的 Element 对象
     */
    dom.create = function(tagName, opt_attributes) {
        var el = document.createElement(tagName),
            attributes = opt_attributes || {};
        return dom.setAttrs(el, attributes);
    };

    /**
     * 从目标元素指定的方向搜索元素
     *
     * @param {HTMLElement|string} element   目标元素或目标元素的id
     * @param {string}             direction 遍历的方向名称，取值为previousSibling,nextSibling
     * @param {string}             start     遍历的开始位置，取值为firstChild,lastChild,previousSibling,nextSibling
     * @meta standard
     * @return {HTMLElement} 搜索到的元素，如果没有找到，返回 null
     */
    dom._matchNode = function (element, direction, start) {
        element = dom.g(element);

        for (var node = element[start]; node; node = node[direction]) {
            if (node.nodeType == 1) {
                return node;
            }
        }

        return null;
    };


    /**
     * 获取目标元素的第一个元素节点
     * @name dom.first
     * @function
     * @grammar dom.first(element)
     * @param {HTMLElement|String} element 目标元素或目标元素的id
     * @see dom.last,dom.prev,dom.next
     * @meta standard
     * @returns {HTMLElement|null} 目标元素的第一个元素节点，查找不到时返回null
     */
    dom.first = function (element) {
        return dom._matchNode(element, 'nextSibling', 'firstChild');
    };


    /**
     * 获得元素的父节点
     * @name dom.getParent
     * @function
     * @grammar dom.getParent(element)
     * @param {HTMLElement|string} element   目标元素或目标元素的id
     * @returns {HTMLElement|null} 父元素，如果找不到父元素，返回null
     */
    dom.getParent = function (element) {
        element = dom._g(element);
        //parentElement在IE下准确，parentNode在ie下可能不准确
        return element.parentElement || element.parentNode || null;
    };

    /**
     * 获取目标元素所属的document对象
     * @name dom.getDocument
     * @function
     * @grammar dom.getDocument(element)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @meta standard
     * @see dom.getWindow
     *             
     * @returns {HTMLDocument} 目标元素所属的document对象
     */
    dom.getDocument = function (element) {
        element = dom.g(element);
        return element.nodeType == 9 ? element : element.ownerDocument || element.document;
    };


    /**
     * 获取目标元素的computed style值。如果元素的样式值不能被浏览器计算，则会返回空字符串（IE）
     *
     * @author berg
     * @name dom.getComputedStyle
     * @function
     * @grammar dom.getComputedStyle(element, key)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {string} key 要获取的样式名
     *
     * @see dom.getStyle
     *             
     * @returns {string} 目标元素的computed style值
     */

    dom.getComputedStyle = function(element, key){
        element = dom._g(element);
        var doc = dom.getDocument(element),
            styles;
        if (doc.defaultView && doc.defaultView.getComputedStyle) {
            styles = doc.defaultView.getComputedStyle(element, null);
            if (styles) {
                return styles[key] || styles.getPropertyValue(key);
            }
        }
        return ''; 
    };

    // 20111204 meizz   去掉一个无用的import browser.ie
    /**
     * 提供给setStyle与getStyle使用
     */
    dom._styleFixer = dom._styleFixer || {};

    /**
     * 提供给setStyle与getStyle使用
     */
    dom._styleFilter = dom._styleFilter || [];



    /**
     * 为获取和设置样式的过滤器
     * @private
     * @meta standard
     */
    dom._styleFilter.filter = function (key, value, method) {
        for (var i = 0, filters = dom._styleFilter, filter; filter = filters[i]; i++) {
            if (filter = filter[method]) {
                value = filter(key, value);
            }
        }

        return value;
    };

    /**
     * 将目标字符串进行驼峰化处理
     * @name string.toCamelCase
     * @function
     * @grammar string.toCamelCase(source)
     * @param {string} source 目标字符串
     * @remark
     * 支持单词以“-_”分隔
     * @meta standard
     *             
     * @returns {string} 驼峰化处理后的字符串
     */
     
     //todo:考虑以后去掉下划线支持？
    string.toCamelCase = function (source) {
        //提前判断，提高getStyle等的效率 thanks xianwei
        if (source.indexOf('-') < 0 && source.indexOf('_') < 0) {
            return source;
        }
        return source.replace(/[-_][^-_]/g, function (match) {
            return match.charAt(1).toUpperCase();
        });
    };


    /**
     * 获取目标元素的样式值
     * @name dom.getStyle
     * @function
     * @grammar dom.getStyle(element, key)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {string} key 要获取的样式名
     * @remark
     * 
     * 为了精简代码，本模块默认不对任何浏览器返回值进行归一化处理（如使用getStyle时，不同浏览器下可能返回rgb颜色或hex颜色），也不会修复浏览器的bug和差异性（如设置IE的float属性叫styleFloat，firefox则是cssFloat）。<br />
     * dom._styleFixer和dom._styleFilter可以为本模块提供支持。<br />
     * 其中_styleFilter能对颜色和px进行归一化处理，_styleFixer能对display，float，opacity，textOverflow的浏览器兼容性bug进行处理。  
     * @shortcut getStyle
     * @meta standard
     * @see dom.setStyle,dom.setStyles, dom.getComputedStyle
     *             
     * @returns {string} 目标元素的样式值
     */
    // TODO
    // 1. 无法解决px/em单位统一的问题（IE）
    // 2. 无法解决样式值为非数字值的情况（medium等 IE）
    dom.getStyle = function (element, key) {
        var dom = dom;

        element = dom.g(element);
        key = string.toCamelCase(key);
        //computed style, then cascaded style, then explicitly set style.
        var value = element.style[key] ||
                    (element.currentStyle ? element.currentStyle[key] : "") || 
                    dom.getComputedStyle(element, key);

        // 在取不到值的时候，用fixer进行修正
        if (!value) {
            var fixer = dom._styleFixer[key];
            if(fixer){
                value = fixer.get ? fixer.get(element) : dom.getStyle(element, fixer);
            }
        }
        
        /* 检查结果过滤器 */
        if (fixer = dom._styleFilter) {
            value = fixer.filter(key, value, 'get');
        }

        return value;
    };


    /**
     * 获取目标元素相对于整个文档左上角的位置
     * @name dom.getPosition
     * @function
     * @grammar dom.getPosition(element)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @meta standard
     *             
     * @returns {Object} 目标元素的位置，键值为top和left的Object。
     */
    dom.getPosition = function (element) {
        element = dom.g(element);
        var doc = dom.getDocument(element), 
            browser = browser,
            getStyle = dom.getStyle,
        // Gecko 1.9版本以下用getBoxObjectFor计算位置
        // 但是某些情况下是有bug的
        // 对于这些有bug的情况
        // 使用递归查找的方式
            BUGGY_GECKO_BOX_OBJECT = browser.isGecko > 0 && 
                                     doc.getBoxObjectFor &&
                                     getStyle(element, 'position') == 'absolute' &&
                                     (element.style.top === '' || element.style.left === ''),
            pos = {"left":0,"top":0},
            viewport = (browser.ie && !browser.isStrict) ? doc.body : doc.documentElement,
            parent,
            box;
        
        if(element == viewport){
            return pos;
        }


        if(element.getBoundingClientRect){ // IE and Gecko 1.9+
            
            //当HTML或者BODY有border width时, 原生的getBoundingClientRect返回值是不符合预期的
            //考虑到通常情况下 HTML和BODY的border只会设成0px,所以忽略该问题.
            box = element.getBoundingClientRect();

            pos.left = Math.floor(box.left) + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);
            pos.top  = Math.floor(box.top)  + Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop);
            
            // IE会给HTML元素添加一个border，默认是medium（2px）
            // 但是在IE 6 7 的怪异模式下，可以被html { border: 0; } 这条css规则覆盖
            // 在IE7的标准模式下，border永远是2px，这个值通过clientLeft 和 clientTop取得
            // 但是。。。在IE 6 7的怪异模式，如果用户使用css覆盖了默认的medium
            // clientTop和clientLeft不会更新
            pos.left -= doc.documentElement.clientLeft;
            pos.top  -= doc.documentElement.clientTop;
            
            var htmlDom = doc.body,
                // 在这里，不使用element.style.borderLeftWidth，只有computedStyle是可信的
                htmlBorderLeftWidth = parseInt(getStyle(htmlDom, 'borderLeftWidth')),
                htmlBorderTopWidth = parseInt(getStyle(htmlDom, 'borderTopWidth'));
            if(browser.ie && !browser.isStrict){
                pos.left -= isNaN(htmlBorderLeftWidth) ? 2 : htmlBorderLeftWidth;
                pos.top  -= isNaN(htmlBorderTopWidth) ? 2 : htmlBorderTopWidth;
            }
        /*
         * 因为firefox 3.6和4.0在特定页面下(场景待补充)都会出现1px偏移,所以暂时移除该逻辑分支
         * 如果 2.0版本时firefox仍存在问题,该逻辑分支将彻底移除. by rocy 2011-01-20
        } else if (doc.getBoxObjectFor && !BUGGY_GECKO_BOX_OBJECT){ // gecko 1.9-

            // 1.9以下的Gecko，会忽略ancestors的scroll值
            // https://bugzilla.mozilla.org/show_bug.cgi?id=328881 and
            // https://bugzilla.mozilla.org/show_bug.cgi?id=330619

            box = doc.getBoxObjectFor(element);
            var vpBox = doc.getBoxObjectFor(viewport);
            pos.left = box.screenX - vpBox.screenX;
            pos.top  = box.screenY - vpBox.screenY;
            */
        } else { // safari/opera/firefox
            parent = element;

            do {
                pos.left += parent.offsetLeft;
                pos.top  += parent.offsetTop;
          
                // safari里面，如果遍历到了一个fixed的元素，后面的offset都不准了
                if (browser.isWebkit > 0 && getStyle(parent, 'position') == 'fixed') {
                    pos.left += doc.body.scrollLeft;
                    pos.top  += doc.body.scrollTop;
                    break;
                }
                
                parent = parent.offsetParent;
            } while (parent && parent != element);

            // 对body offsetTop的修正
            if(browser.opera > 0 || (browser.isWebkit > 0 && getStyle(element, 'position') == 'absolute')){
                pos.top  -= doc.body.offsetTop;
            }

            // 计算除了body的scroll
            parent = element.offsetParent;
            while (parent && parent != doc.body) {
                pos.left -= parent.scrollLeft;
                // see https://bugs.opera.com/show_bug.cgi?id=249965
    //            if (!b.opera || parent.tagName != 'TR') {
                if (!browser.opera || parent.tagName != 'TR') {
                    pos.top -= parent.scrollTop;
                }
                parent = parent.offsetParent;
            }
        }

        return pos;
    };

    /**
     * 获得元素中的文本内容。
     * @name dom.getText
     * @function
     * @grammar dom.getText(element)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @version 1.3
     *             
     * @returns {String} 元素中文本的内容      
     */
    dom.getText = function (element) {
        var ret = "", childs, i=0, l;

        element = _g(element);

        //  text 和 CDATA 节点，取nodeValue
        if ( element.nodeType === 3 || element.nodeType === 4 ) {
            ret += element.nodeValue;
        } else if ( element.nodeType !== 8 ) {// 8 是 comment Node
            childs = element.childNodes;
            for(l = childs.length; i < l; i++){
                ret += dom.getText(childs[i]);
            }
        }

        return ret;
    };

    /**
     * 判断元素是否拥有指定的className
     * @name dom.hasClass
     * @function
     * @grammar dom.hasClass(element, className)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {string} className 要判断的className，可以是用空格拼接的多个className
     * @version 1.2
     * @remark
     * 对于参数className，支持空格分隔的多个className
     * @see dom.addClass, dom.removeClass
     * @meta standard
     * @returns {Boolean} 是否拥有指定的className，如果要查询的classname有一个或多个不在元素的className中，返回false
     */
    dom.hasClass = function (element, className) {
        element = dom.g(element);

        // 对于 textNode 节点来说没有 className
        if(!element || !element.className) return false;

        var classArray = string.trim(className).split(/\s+/), 
            len = classArray.length;

        className = element.className.split(/\s+/).join(" ");

        while (len--) {
            if(!(new RegExp("(^| )" + classArray[len] + "( |\x24)")).test(className)){
                return false;
            }
        }
        return true;
    };

    /**
     * 将目标元素添加到基准元素之后
     * @name dom.insertAfter
     * @function
     * @grammar dom.insertAfter(newElement, existElement)
     * @param {HTMLElement|string} newElement 被添加的目标元素
     * @param {HTMLElement|string} existElement 基准元素
     * @meta standard
     * @see dom.insertBefore
     *             
     * @returns {HTMLElement} 被添加的目标元素
     */
    dom.insertAfter = function (newElement, existElement) {
        var g, existParent;
        g = dom._g;
        newElement = g(newElement);
        existElement = g(existElement);
        existParent = existElement.parentNode;
        
        if (existParent) {
            existParent.insertBefore(newElement, existElement.nextSibling);
        }
        return newElement;
    };

    /**
     * 将目标元素添加到基准元素之前
     * @name dom.insertBefore
     * @function
     * @grammar dom.insertBefore(newElement, existElement)
     * @param {HTMLElement|string} newElement 被添加的目标元素
     * @param {HTMLElement|string} existElement 基准元素
     * @meta standard
     * @see dom.insertAfter
     *             
     * @returns {HTMLElement} 被添加的目标元素
     */
    dom.insertBefore = function (newElement, existElement) {
        var g, existParent;
        g = dom._g;
        newElement = g(newElement);
        existElement = g(existElement);
        existParent = existElement.parentNode;

        if (existParent) {
            existParent.insertBefore(newElement, existElement);
        }

        return newElement;
    };

    /**
     * 在目标元素的指定位置插入HTML代码
     * @name dom.insertHTML
     * @function
     * @grammar dom.insertHTML(element, position, html)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {string} position 插入html的位置信息，取值为beforeBegin,afterBegin,beforeEnd,afterEnd
     * @param {string} html 要插入的html
     * @remark
     * 
     * 对于position参数，大小写不敏感<br>
     * 参数的意思：beforeBegin&lt;span&gt;afterBegin   this is span! beforeEnd&lt;/span&gt; afterEnd <br />
     * 此外，如果使用本函数插入带有script标签的HTML字符串，script标签对应的脚本将不会被执行。
     * 
     * @shortcut insertHTML
     * @meta standard
     *             
     * @returns {HTMLElement} 目标元素
     */
    dom.insertHTML = function (element, position, html) {
        element = dom.g(element);
        var range,begin;

        //在opera中insertAdjacentHTML方法实现不标准，如果DOMNodeInserted方法被监听则无法一次插入多element
        //by lixiaopeng @ 2011-8-19
        if (element.insertAdjacentHTML && !browser.opera) {
            element.insertAdjacentHTML(position, html);
        } else {
            // 这里不做"undefined" != typeof(HTMLElement) && !window.opera判断，其它浏览器将出错？！
            // 但是其实做了判断，其它浏览器下等于这个函数就不能执行了
            range = element.ownerDocument.createRange();
            // FF下range的位置设置错误可能导致创建出来的fragment在插入dom树之后html结构乱掉
            // 改用range.insertNode来插入html, by wenyuxiang @ 2010-12-14.
            position = position.toUpperCase();
            if (position == 'AFTERBEGIN' || position == 'BEFOREEND') {
                range.selectNodeContents(element);
                range.collapse(position == 'AFTERBEGIN');
            } else {
                begin = position == 'BEFOREBEGIN';
                range[begin ? 'setStartBefore' : 'setEndAfter'](element);
                range.collapse(begin);
            }
            range.insertNode(range.createContextualFragment(html));
        }
        return element;
    };


    /**
     * 获取目标元素的最后一个元素节点
     * @name dom.last
     * @function
     * @grammar dom.last(element)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @see dom.first,dom.prev,dom.next
     *             
     * @returns {HTMLElement|null} 目标元素的最后一个元素节点，查找不到时返回null
     */
    dom.last = function (element) {
        return dom._matchNode(element, 'previousSibling', 'lastChild');
    };

    /**
     * 获取目标元素的下一个兄弟元素节点
     * @name dom.next
     * @function
     * @grammar dom.next(element)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @see dom.first,dom.last,dom.prev
     * @meta standard
     * @returns {HTMLElement|null} 目标元素的下一个兄弟元素节点，查找不到时返回null
     */
    dom.next = function (element) {
        return dom._matchNode(element, 'nextSibling', 'nextSibling');
    };

    /**
     * 获取目标元素的上一个兄弟元素节点
     * @name dom.prev
     * @function
     * @grammar dom.prev(element)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @see dom.first,dom.last,dom.next
     *             
     *             
     * @returns {HTMLElement|null} 目标元素的上一个兄弟元素节点，查找不到时返回null
     */
    dom.prev = function (element) {
        return dom._matchNode(element, 'previousSibling', 'previousSibling');
    };

    /**
     * 使函数在页面dom节点加载完毕时调用
     * @author allstar
     * @name dom.ready
     * @function
     * @grammar dom.ready(callback)
     * @param {Function} callback 页面加载完毕时调用的函数.
     * @remark
     * 如果有条件将js放在页面最底部, 也能达到同样效果，不必使用该方法。
     * @meta standard
     */
    (function() {

        var ready = dom.ready = function() {
            var readyBound = false,
                readyList = [],
                DOMContentLoaded;

            if (document.addEventListener) {
                DOMContentLoaded = function() {
                    document.removeEventListener('DOMContentLoaded', DOMContentLoaded, false);
                    ready();
                };

            } else if (document.attachEvent) {
                DOMContentLoaded = function() {
                    if (document.readyState === 'complete') {
                        document.detachEvent('onreadystatechange', DOMContentLoaded);
                        ready();
                    }
                };
            }
            /**
             * @private
             */
            function ready() {
                if (!ready.isReady) {
                    ready.isReady = true;
                    for (var i = 0, j = readyList.length; i < j; i++) {
                        readyList[i]();
                    }
                }
            }
            /**
             * @private
             */
            function doScrollCheck(){
                try {
                    document.documentElement.doScroll("left");
                } catch(e) {
                    setTimeout( doScrollCheck, 1 );
                    return;
                }   
                ready();
            }
            /**
             * @private
             */
            function bindReady() {
                if (readyBound) {
                    return;
                }
                readyBound = true;

                if (document.readyState === 'complete') {
                    ready.isReady = true;
                } else {
                    if (document.addEventListener) {
                        document.addEventListener('DOMContentLoaded', DOMContentLoaded, false);
                        window.addEventListener('load', ready, false);
                    } else if (document.attachEvent) {
                        document.attachEvent('onreadystatechange', DOMContentLoaded);
                        window.attachEvent('onload', ready);

                        var toplevel = false;

                        try {
                            toplevel = window.frameElement == null;
                        } catch (e) {}

                        if (document.documentElement.doScroll && toplevel) {
                            doScrollCheck();
                        }
                    }
                }
            }
            bindReady();

            return function(callback) {
                ready.isReady ? callback() : readyList.push(callback);
            };
        }();

        ready.isReady = false;
    })();

    /**
     * 从DOM树上移除目标元素
     * @name dom.remove
     * @function
     * @grammar dom.remove(element)
     * @param {HTMLElement|string} element 需要移除的元素或元素的id
     * @remark
     * <b>注意：</b>对于移除的dom元素，IE下会释放该元素的空间，继续使用该元素的引用进行操作将会引发不可预料的问题。
     * @meta standard
     */
    dom.remove = function (element) {
        element = dom._g(element);
        var tmpEl = element.parentNode;
        //去掉了对ie下的特殊处理：创建一个div，appendChild，然后div.innerHTML = ""
        tmpEl && tmpEl.removeChild(element);
    };

    /**
     * 移除目标元素的className
     * @name dom.removeClass
     * @function
     * @grammar dom.removeClass(element, className)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {string} className 要移除的className，允许同时移除多个class，中间使用空白符分隔
     * @remark
     * 使用者应保证提供的className合法性，不应包含不合法字符，className合法字符参考：http://www.w3.org/TR/CSS2/syndata.html。
     * @shortcut removeClass
     * @meta standard
     * @see dom.addClass
     *             
     * @returns {HTMLElement} 目标元素
     */
    dom.removeClass = function (element, className) {
        element = dom.g(element);

        var oldClasses = element.className.split(/\s+/),
            newClasses = className.split(/\s+/),
            lenOld,
            lenDel = newClasses.length,
            j,
            i = 0;
        //考虑到同时删除多个className的应用场景概率较低,故放弃进一步性能优化 
        // by rocy @1.3.4
        for (; i < lenDel; ++i){
            for(j = 0, lenOld = oldClasses.length; j < lenOld; ++j){
                if(oldClasses[j] == newClasses[i]){
                    oldClasses.splice(j, 1);
                    break;
                }
            }
        }
        element.className = oldClasses.join(' ');
        return element;
    };


    /**
     * 设置目标元素的style样式值
     * @name dom.setStyle
     * @function
     * @grammar dom.setStyle(element, key, value)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {string} key 要设置的样式名
     * @param {string} value 要设置的样式值
     * @remark
     * 
                为了精简代码，本模块默认不对任何浏览器返回值进行归一化处理（如使用getStyle时，不同浏览器下可能返回rgb颜色或hex颜色），也不会修复浏览器的bug和差异性（如设置IE的float属性叫styleFloat，firefox则是cssFloat）。<br />
    dom._styleFixer和dom._styleFilter可以为本模块提供支持。<br />
    其中_styleFilter能对颜色和px进行归一化处理，_styleFixer能对display，float，opacity，textOverflow的浏览器兼容性bug进行处理。
            
     * @shortcut setStyle
     * @meta standard
     * @see dom.getStyle,dom.setStyles
     *             
     * @returns {HTMLElement} 目标元素
     */
    dom.setStyle = function (element, key, value) {
        var dom = dom, fixer;
        
        // 放弃了对firefox 0.9的opacity的支持
        element = dom.g(element);
        key = string.toCamelCase(key);

        if (fixer = dom._styleFilter) {
            value = fixer.filter(key, value, 'set');
        }

        fixer = dom._styleFixer[key];
        (fixer && fixer.set) ? fixer.set(element, value) : (element.style[fixer || key] = value);

        return element;
    };



    /**
     * 批量设置目标元素的style样式值
     * @name dom.setStyles
     * @function
     * @grammar dom.setStyles(element, styles)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {Object} styles 要设置的样式集合
     * @shortcut setStyles
     * @meta standard
     * @see dom.setStyle,dom.getStyle
     *             
     * @returns {HTMLElement} 目标元素
     */
    dom.setStyles = function (element, styles) {
        element = dom.g(element);

        for (var key in styles) {
            dom.setStyle(element, key, styles[key]);
        }

        return element;
    };

    // 声明快捷方法
    setStyles = dom.setStyles;

    /**
     * 提供给setStyle与getStyle使用
     * @meta standard
     */
    dom._styleFilter[dom._styleFilter.length] = {
        set: function (key, value) {
            if (value.constructor == Number 
                && !/zIndex|fontWeight|opacity|zoom|lineHeight/i.test(key)){
                value = value + "px";
            }

            return value;
        }
    };


    /**
     * 设置目标元素的top和left值到用户指定的位置
     * 
     * @name dom.setPosition
     * @function
     * @grammar dom.setPosition(element, position)
     * 
     * @param {HTMLElement|string}  element     目标元素或目标元素的id
     * @param {object}              position    位置对象 {top: {number}, left : {number}}
     *
     * @return {HTMLElement}  进行设置的元素
     */
    dom.setPosition = function (element, position) {
        return dom.setStyles(element, {
            left : position.left - (parseFloat(dom.getStyle(element, "margin-left")) || 0),
            top : position.top - (parseFloat(dom.getStyle(element, "margin-top")) || 0)
        });
    };

    /**
     * 添加或者删除一个节点中的指定class，如果已经有就删除，否则添加
     * @name dom.toggleClass
     * @function
     * @grammar dom.toggleClass(element, className)
     * @param {HTMLElement|string} element 目标元素或目标元素的id
     * @param {String} className 指定的className。允许同时添加多个class，中间使用空白符分隔
     * @version 1.3
     * @remark
     * 
     * 传入多个class时，只要其中有一个class不在当前元素中，则添加所有class，否则删除所有class。
     */

    dom.toggleClass = function (element, className) {
        if(dom.hasClass(element, className)){
            dom.removeClass(element, className);
        }else{
            dom.addClass(element, className);
        }
    };

    /**
     * shortcut
     */
    T.g = T.dom.g;
    T.hasClass = T.dom.hasClass;
    T.addClass = T.dom.addClass;
    T.removeClass = T.dom.removeClass;
    T.toggleClass = T.dom.toggleClass;
    
})(window, T, T.string, T.string);